package xgo

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
)

type TryCatch struct {
	exception Exception
}

type Exception struct {
	err     error
	message string
	code    int
}

func Try(callable func()) (tc TryCatch) {

	defer func() {
		if panicerr := recover(); panicerr != nil {

			if strings.Index(reflect.TypeOf(panicerr).String(), ".Exception") != -1 {
				tc.exception = panicerr.(Exception)
			} else {
				buildException(&(tc.exception), "Throw Exception :"+fmt.Sprint(panicerr), 500)
			}

		}
	}()
	callable()
	return
}

func buildException(exp *Exception, info string, code ...int) {
	exp.err = errors.New(info)
	exp.message = info
	if len(code) > 0 {
		exp.code = code[0]
	} else {
		exp.code = 500
	}
}

func ThrowException(info string, code ...int) (exception Exception) {
	buildException(&exception, info, code...)
	panic(exception)
}

var Panic = ThrowException

func (exp Exception) GetMessage() string {
	return exp.message
}

func (exp Exception) GetCode() int {
	return exp.code
}

func (exp Exception) GetError() error {
	return exp.err
}

func (tc TryCatch) Catch(callable func(exception Exception)) TryCatch {
	if tc.exception.err != nil {
		callable(tc.exception)
	}
	return tc
}

func (tc TryCatch) Finally(callable func()) {
	callable()
}
